feat(validation): add HIL validation for NUCLEO-WB55RG/WBA55CG and fix the driver bugs it found - #95
Conversation
The hardware-in-the-loop validation app builds on EMIL's services.hil and services.hil.commands, added after the previously pinned commit. The range only adds those libraries, Terminal command hooks, DutyCycle::FromRatio and an ISB after disabling an NVIC interrupt; no interface hal-st implements changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
The destructor always called DisableClockUart(uartIndex), so destroying LPUART1 switched off USART1's clock instead (and left LPUART1 clocked). On the Nucleo-WB55/WBA55 USART1 is the ST-LINK virtual COM port. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
…UCLEO-WBA55CG Mirror hal-ti's validation app: a firmware that exposes the hal-st drivers through EMIL's services/hil terminal so a host suite and an Analog Discovery 3 can exercise them on real hardware. The command set is in validation/PROTOCOL.md. - target hal_st.validation_firmware, built for stm32wb55 and stm32wba55 with HALST_BUILD_EXAMPLES (on in every preset) - terminal on USART1 (ST-LINK VCP) with UartStmDuplexDma at 921600 8N1 - board profiles with alias tables, reserved pins, DMA request lines and clocks; STM32 pin factory over the generated pinout tables, guarding unbonded pins and shared EXTI lines - factories for GPIO, UART (UartStm, UartStmDma, UartStmDuplexDma, SynchronousUartStm, LPUART), SPI (SpiMasterStm, SpiMasterStmDma, SynchronousSpiMasterStm, GPIO chip select), ADC (one-shot and timer-triggered AdcDmaMultiChannelStm), PWM (PwmStm, SynchronousPwmStm), encoder (timer and LPTIM, plus qei.index) and the WWDG - comparator, CAN, EEPROM and Ethernet commands answer ERR unsupported - devcontainer maps host.docker.internal for the bridge setup, and a stm32wba55cg debug configuration is added Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
…r review - SPI: close waits up to 10 ms for an in-flight transfer before destroying the driver; SpiMasterStm schedules its completion with no stale-event guard, and a WB55 DMA channel left running ignores the next open - UART: USART1 answers busy only after the argument checks, so argument errors keep coming first - ADC: constant-time trigger timing instead of a prescaler search that blocked the event loop; interrupts stay masked through a triggered stop; rate without timer is a usage error before range checks - encoder: lp=1 rejects cap/offset/invb before parsing their values Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
…uite Port hal-ti's validation host to hal-st: a Python package that drives the validation firmware terminal and a Digilent Analog Discovery 3 through ad3-waveforms-bench (pinned to the same commit as hal-ti). - board files for NUCLEO-WB55RG and NUCLEO-WBA55CG: alias tables, clocks, AD3 wiring sets (bundle1, plus bundle2 for the WB55 LPTIM encoder) and every test parameter matrix - typed firmware API, STM32 expectation math (PWM quantisation and range, SPI prescaler, UART baud-rate register limits, WWDG period, ADC codes), pairwise/full parameter depth, and a fake firmware for --fake runs - HIL tests for system, GPIO, PWM, UART, SPI, ADC, encoder, watchdog and the unsupported groups; unit tests for the harness itself - known_gaps in the board files: driver bugs found while writing the firmware skip (when they abort or hang the board) or xfail the tests they affect; --run-known-gaps runs them anyway - validation/README.md: setup, wiring tables, running, bridge mode and the known driver gaps; AGENTS.md and CLAUDE.md point to the new app Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
- ConfigureTimeBase initialised the timer with Period = 0, which fails IS_TIM_PERIOD under USE_FULL_ASSERT and aborted every construction. It now initialises with Period = 1 and loads the real period in Start. - The counter direction is written only after CMS and SMS are cleared, as CR1.DIR ignores writes while centre-aligned or in encoder mode. - Centre-aligned: ARR is ticks / 2 (period 2 x ARR) instead of ticks / 2 - 1, and duty is scaled to ARR; edge-aligned down-counting compensates the extra active tick. - TRGO (MMS/MMS2), BDTR and the BKIN source are rewritten on every construction, so dead time, break, idle and trigger settings of an earlier user no longer survive. BKINP stays non-inverted, so an active-low break is no longer inverted twice. - An update event on the first Start loads the preloaded ARR/CCR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
On the WBA ADC4 (CHSELR sequencer, common sampling times): - AdcDmaMultiChannelStm passed ADC_SAMPLETIME_x where HAL_ADC_ConfigChannel takes ADC_SAMPLINGTIME_COMMON_1/2 (assert, abort). Per-channel sampling times are now mapped onto the two common groups; a sequence can use at most two distinct sampling times, and MaxChannels is 8 on ADC4. - Scan mode and NbrOfConversion are set for the sequence, and the sequencer length is written with the LL encoding instead of the rank count. - AdcStm::SelectSingleConversion restores single-channel scan and SMP1 for the single-pin, temperature and timer-triggered DMA users of the same AdcStm; the temperature path uses the common sampling time. - The ADC triggers from TIM1 TRGO2 there, so AdcTimerTriggeredBase now configures TRGO2 = update for TIM1 (new TimerBaseStm::Trigger:: TriggerOutput2). - The trigger table lacked a TIM10 slot, which shifted the triggers of TIM11 and later timers by one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
CSTART was only set when a byte was written to TXDR, so a receive-only first transfer on H5/WBA never started (SpiMasterStm timed out, SynchronousSpiMasterStm spun forever). CSTART is now set once per transfer after the interrupts are enabled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
- Stream-based DMA (F4/F7) sets TCIF once clearing EN takes effect, which reported an aborted transfer as complete. StopTransfer now masks TC/HT, waits for EN to clear, clears the flags and restores the enables, as HAL_DMA_Abort does. - GPDMA: SUSPF is cleared after the channel reset, so a stale flag no longer ends the next suspend wait before the channel is suspended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
- SWAP is always written, so a swapped instance is no longer swapped for later users (UartStm, SynchronousUartStm). - Destructors clear TXEIE/TCIE/RXNEIE (and RTOEN for the duplex DMA variant), and ~UartStmDma stops its transmit DMA, so a close during a stalled send no longer leaves an interrupt storm for the next user. - CR1 enable bits are set and cleared atomically: a TXEIE clear from the interrupt during ReceiveData's read-modify-write was undone. - A receive overrun is cleared instead of asserting (UartStm) or being left set (SynchronousUartStm), which looped on the ORE interrupt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
EnableInterrupt wrote the compacted hal::Port value into EXTICR, which selects the wrong port for ports after a gap (port H on WB/WBA). It now writes GPIO_GET_INDEX of the port, with the field width taken from the CMSIS EXTI/SYSCFG EXTICR positions (8 bits on G0, H5 and WBA). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
HAL_LPTIM_Init ORs the clock and trigger filters into CFGR without clearing them, so a previous user's filter persisted. The LPTIM is now reset through RCC before it is initialised. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
- Remove the fixed known gaps from both board files; only the SynchronousUartStm CTS-held send (WBA55) remains. - PWM: range check and host expectations follow the fixed ARR (ticks - 1 edge, ticks / 2 centre); the centre-period xfail is gone. - GPIO: port H interrupts are no longer refused. - README and PROTOCOL list the remaining gaps and the PWM range. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
✅
|
| Descriptor | Linter | Files | Fixed | Errors | Max errors | Warnings | Elapsed time |
|---|---|---|---|---|---|---|---|
| ✅ ACTION | actionlint | 5 | 0 | 0 | 0.15s | ||
| ✅ CPP | clang-format | 45 | 6 | 0 | 0 | 2.17s | |
| ✅ CPP | cppcheck | 45 | 0 | 0 | 1.17s | ||
| ✅ DOCKERFILE | hadolint | 1 | 0 | 0 | 0.04s | ||
| ✅ JSON | jsonlint | 9 | 0 | 0 | 0.11s | ||
| ✅ JSON | prettier | 9 | 3 | 0 | 0 | 1.53s | |
| markdownlint | 18 | 1 | 20 | 0 | 2.34s | ||
| ✅ MARKDOWN | markdown-table-formatter | 18 | 1 | 0 | 0 | 1.24s | |
| ✅ REPOSITORY | betterleaks | yes | no | no | 1.27s | ||
| ✅ REPOSITORY | checkov | yes | no | no | 18.48s | ||
| ✅ REPOSITORY | git_diff | yes | no | no | 0.96s | ||
| ✅ REPOSITORY | grype | yes | no | no | 101.45s | ||
| ✅ REPOSITORY | ls-lint | yes | no | no | 0.01s | ||
| osv-scanner | yes | no | 1 | 0.7s | |||
| ✅ REPOSITORY | secretlint | yes | no | no | 1.5s | ||
| ✅ REPOSITORY | syft | yes | no | no | 2.37s | ||
| ✅ REPOSITORY | trivy | yes | no | no | 13.05s | ||
| ✅ REPOSITORY | trivy-sbom | yes | no | no | 0.3s | ||
| ✅ REPOSITORY | trufflehog | yes | no | no | 4.68s | ||
| lychee | 50 | 6 | 0 | 16.44s | |||
| ✅ YAML | prettier | 8 | 1 | 0 | 0 | 1.64s | |
| ✅ YAML | v8r | 8 | 0 | 0 | 5.28s | ||
| ✅ YAML | yamllint | 8 | 0 | 0 | 0.55s |
Detailed Issues
⚠️ SPELL / lychee - 6 errors
📝 Summary
---------------------
🔍 Total..........282
🔗 Unique.........258
✅ Successful.....271
⏳ Timeouts.........0
🔀 Redirected.....111
👻 Excluded.........5
❓ Unknown..........0
🚫 Errors...........6
⛔ Unsupported......6
Errors in .github/agents/orchestrator.agent.md
[ERROR] file://.github/copilot-instructions.md (at 52:23) | File not found. Check if file exists and path is correct
[ERROR] file://hal_st/cortex/InterruptCortex.hpp (at 56:22) | File not found. Check if file exists and path is correct
Errors in .github/ISSUE_TEMPLATE/add-or-update-hal-driver.md
[ERROR] http://mcd.rou.st.com/modules.php?name=mcu (at 28:63) | Connection failed. Check network connectivity and firewall settings
Errors in README.md
[404] https://api.securityscorecards.dev/projects/github.com/embedded-pro/hal-st (at 3:199) | Rejected status code: 404 Not Found
[ERROR] https://st.com/ (at 5:93) | HTTP/2 protocol error. Server may not support HTTP/2 properly | Followed 1 redirect. Redirects: https://st.com/ --[301]--> https://www.st.com/
Errors in validation/README.md
[403] https://digilent.com/reference/software/waveforms/waveforms-3/start (at 164:12) | Rejected status code: 403 Forbidden
Hint: Followed 111 redirects. You might want to consider replacing redirecting URLs with the resolved URLs. Use verbose mode (`-v`/`-vv`) to see redirection details.
Hint: You can configure accepted/rejected response codes with `-a` or `--accept`
⚠️ MARKDOWN / markdownlint - 20 errors
.github/agents/executor.agent.md:11 error MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "You are the executor agent for..."]
.github/agents/orchestrator.agent.md:18:401 error MD013/line-length Line length [Expected: 400; Actual: 420]
.github/agents/orchestrator.agent.md:18 error MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "You are the orchestrator agent..."]
.github/agents/planner.agent.md:11 error MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "You are the planner agent for ..."]
.github/agents/planner.agent.md:39 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
.github/agents/reviewer.agent.md:14 error MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "You are the reviewer agent for..."]
.github/agents/reviewer.agent.md:122 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
.github/instructions/hal-st-cpp.instructions.md:18 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
.github/ISSUE_TEMPLATE/add-or-update-hal-driver.md:10 error MD025/single-title/single-h1 Multiple top-level headings in the same document [Context: "How to import a HAL driver"]
.github/prompts/orchestrate.prompt.md:8 error MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "Start a new development workfl..."]
CHANGELOG.md:83 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "⚠ BREAKING CHANGES"]
CHANGELOG.md:87 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Features"]
CHANGELOG.md:94 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Bug Fixes"]
CHANGELOG.md:103 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Features"]
CHANGELOG.md:122 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Bug Fixes"]
CHANGELOG.md:140 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "⚠ BREAKING CHANGES"]
CHANGELOG.md:144 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Features"]
CHANGELOG.md:151 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Features"]
CHANGELOG.md:162 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Bug Fixes"]
CLAUDE.md:1 error MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "hal-st — Claude Instructions"]
⚠️ REPOSITORY / osv-scanner - 1 warning
Scanning dir .
Starting filesystem walk for root: /
End status: 62 dirs visited, 516 inodes visited, 0 Extract calls, 6.388526ms elapsed, 6.388725ms wall time
No package sources found, --help for usage information.
[REPOSITORY_OSV_SCANNER_ERROR_NO_PACKAGE_SOURCES] osv-scanner found no lockfiles, manifests, or SBOMs to scan in the repository.
This is a configuration/scope issue, not a vulnerability finding.
Resolutions:
- Verify the repository actually contains a supported lockfile (package-lock.json, go.sum, Gemfile.lock, Pipfile.lock, etc.) at the scanned path.
- If this is expected for some sub-projects, disable osv-scanner for the affected paths or mark it non-blocking via `DISABLE_ERRORS_LINTERS`.
Notices
REPOSITORY_GITLEAKS, REPOSITORY_KICS. See Removed linters to find their replacements.
See detailed reports in MegaLinter artifacts
Your project could benefit from a custom flavor, which would allow you to run only the linters you need, and thus improve runtime performances. (Skip this info by defining FLAVOR_SUGGESTIONS: false)
- Documentation: Custom Flavors
- Command:
npx mega-linter-runner@10.1.0 --custom-flavor-setup --custom-flavor-linters ACTION_ACTIONLINT,CPP_CPPCHECK,CPP_CLANG_FORMAT,DOCKERFILE_HADOLINT,JSON_JSONLINT,JSON_PRETTIER,MARKDOWN_MARKDOWNLINT,MARKDOWN_MARKDOWN_TABLE_FORMATTER,REPOSITORY_CHECKOV,REPOSITORY_GIT_DIFF,REPOSITORY_BETTERLEAKS,REPOSITORY_GRYPE,REPOSITORY_LS_LINT,REPOSITORY_OSV_SCANNER,REPOSITORY_SECRETLINT,REPOSITORY_SYFT,REPOSITORY_TRIVY,REPOSITORY_TRIVY_SBOM,REPOSITORY_TRUFFLEHOG,SPELL_LYCHEE,YAML_PRETTIER,YAML_YAMLLINT,YAML_V8R

Show us your support by starring ⭐ the repository
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
UART destructors omit required deinitialization/clock cleanup, and ADC4 can silently misapply sampling times for repeated channels.
Review effort: Balanced
Findings: 3
Open (3)
What changed in this PR
Adds WB55/WBA55 hardware-in-the-loop validation infrastructure and fixes driver defects exposed by it.
Changes:
- Adds validation firmware, host tooling, board profiles, and HIL tests.
- Fixes PWM, ADC, UART, SPI, DMA, GPIO, timer, and QEI behavior.
- Updates build, debugging, and contributor documentation.
| File | Description |
|---|---|
validation/host/tests/unit/test_terminal_alignment.py |
Tests delayed terminal replies. |
validation/host/tests/unit/test_protocol.py |
Tests pins, aliases, and responses. |
validation/host/tests/unit/test_pairwise.py |
Tests matrix generation. |
validation/host/tests/unit/test_known_gaps.py |
Tests known-gap handling. |
validation/host/tests/unit/test_firmware.py |
Tests host command formatting. |
validation/host/tests/hil/test_watchdog.py |
Validates watchdog behavior. |
validation/host/tests/hil/test_unsupported.py |
Validates unsupported commands. |
validation/host/tests/hil/test_system.py |
Validates system protocol behavior. |
validation/host/tests/hil/test_spi.py |
Validates SPI drivers. |
validation/host/tests/hil/test_qei.py |
Validates timer/LPTIM QEI. |
validation/host/tests/hil/test_gpio.py |
Validates GPIO and EXTI. |
validation/host/tests/hil/test_adc.py |
Validates ADC sequences and triggers. |
validation/host/pyproject.toml |
Defines host package and tooling. |
validation/host/hal_st_validation/protocol.py |
Implements pin protocol helpers. |
validation/host/hal_st_validation/pairwise.py |
Implements test-matrix generation. |
validation/host/hal_st_validation/console.py |
Adds validation console entry point. |
validation/host/hal_st_validation/__init__.py |
Exports host APIs. |
validation/host/.gitignore |
Ignores Python artifacts. |
validation/firmware/WatchDogFactory.hpp |
Declares watchdog factory. |
validation/firmware/WatchDogFactory.cpp |
Implements watchdog validation adapter. |
validation/firmware/UnsupportedGroups.hpp |
Declares unsupported groups. |
validation/firmware/UnsupportedGroups.cpp |
Registers unsupported commands. |
validation/firmware/UartFactory.hpp |
Declares UART factory. |
validation/firmware/TimerAllocation.hpp |
Declares timer ownership tracking. |
validation/firmware/TimerAllocation.cpp |
Implements timer ownership. |
validation/firmware/SpiFactory.hpp |
Declares SPI factory. |
validation/firmware/SpiFactory.cpp |
Implements SPI validation adapters. |
validation/firmware/QeiFactory.hpp |
Declares QEI factory. |
validation/firmware/QeiFactory.cpp |
Implements QEI validation adapters. |
validation/firmware/PwmFactory.hpp |
Declares PWM factory. |
validation/firmware/PinFactoryStm.hpp |
Declares managed validation pins. |
validation/firmware/PinFactoryStm.cpp |
Implements pin ownership and capabilities. |
validation/firmware/PeripheralClocks.hpp |
Declares timer clock helpers. |
validation/firmware/PeripheralClocks.cpp |
Resolves timer clocks. |
validation/firmware/Main.cpp |
Composes validation firmware. |
validation/firmware/Console.hpp |
Declares terminal infrastructure. |
validation/firmware/Console.cpp |
Configures validation UART. |
validation/firmware/CMakeLists.txt |
Builds validation firmware. |
validation/firmware/BoardTypes.hpp |
Defines shared board types. |
validation/firmware/boards/stm32wba55/BoardProfile.hpp |
Defines WBA55 board mapping. |
validation/firmware/boards/stm32wb55/BoardProfile.hpp |
Defines WB55 board mapping. |
validation/firmware/BoardInfoStm.hpp |
Declares board information provider. |
validation/firmware/BoardInfoStm.cpp |
Reports board and reset information. |
validation/firmware/AdcFactory.hpp |
Declares ADC factory. |
validation/firmware/AdcFactory.cpp |
Implements ADC validation sequences. |
validation/CMakeLists.txt |
Includes validation firmware. |
hal_st/synchronous_stm32fxxx/SynchronousUartStm.cpp |
Updates UART cleanup and overrun handling. |
hal_st/synchronous_stm32fxxx/SynchronousSpiMasterStm.cpp |
Starts SPI v2 transfers correctly. |
hal_st/synchronous_stm32fxxx/SynchronousQuadratureEncoderLpTimStm.cpp |
Resets LPTIM before initialization. |
hal_st/stm32fxxx/UartStmDuplexDma.cpp |
Clears receiver-timeout state. |
hal_st/stm32fxxx/UartStmDma.cpp |
Stops transmit DMA during destruction. |
hal_st/stm32fxxx/UartStm.cpp |
Updates UART initialization and interrupts. |
hal_st/stm32fxxx/TimerStm.hpp |
Adds TRGO2 configuration. |
hal_st/stm32fxxx/TimerStm.cpp |
Applies TRGO2 configuration. |
hal_st/stm32fxxx/SpiMasterStm.cpp |
Starts SPI v2 transfers once. |
hal_st/stm32fxxx/PwmStm.hpp |
Documents down-counting limitation. |
hal_st/stm32fxxx/PwmStm.cpp |
Corrects PWM initialization and scaling. |
hal_st/stm32fxxx/GpioStm.cpp |
Corrects EXTI port encoding. |
hal_st/stm32fxxx/DmaStm.cpp |
Corrects DMA cancellation/reset handling. |
hal_st/stm32fxxx/AnalogToDigitalPinStm.hpp |
Exposes single-conversion selection. |
hal_st/stm32fxxx/AnalogToDigitalPinStm.cpp |
Restores single-channel ADC state. |
hal_st/stm32fxxx/AdcTimerTriggeredBase.cpp |
Adds TIM10 and TRGO2 support. |
hal_st/stm32fxxx/AdcDmaStm.cpp |
Restores single-conversion mode. |
hal_st/stm32fxxx/AdcDmaMultiChannelStm.hpp |
Limits ADC4 sequences to eight ranks. |
hal_st/stm32fxxx/AdcDmaMultiChannelStm.cpp |
Configures ADC sequences and sampling groups. |
CMakeLists.txt |
Updates EMIL and includes validation. |
CLAUDE.md |
Documents validation workflow. |
AGENTS.md |
Documents validation architecture and commands. |
.vscode/launch.json |
Adds WBA55 debugging. |
.devcontainer/devcontainer.json |
Exposes the host debugger. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…der positions PB3 (TIM2 CH2, SWO) is on no header of a stock NUCLEO-WB55RG: CN10-30 carries PB13 unless SB12/SB13 are reworked (UM2435 Rev 2, Fig. 8, Table 11). TIM2 CH2 and the default encoder B move to PA1 (A2, CN7-32 via SB14), the only other TIM2 CH2 pin. Every WB55 wiring row now names its morpho pin and Arduino socket from UM2435 Rev 2 (MB1355C), plus the ground pins, the solder bridges on the path, the D10 bridge note (PA4 by default, confirmed) and the terminal pins to keep free. The loopback note says what the SPI tests do with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
AGENTS.md asks for HAL_FOO_DeInit and a clock disable in every driver destructor. UartStm gated the clock without HAL_UART_DeInit, and SynchronousUartStm/SynchronousUartStmSendOnly did neither. The explicit interrupt-enable clear stays: the F4 HAL_UART_DeInit leaves CR1 as is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
The sampling time (SMPRx, or SMPSEL on ADC4) belongs to the channel, not to the rank, so configuring a repeated channel with another sampling time silently changed the earlier rank too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
Formatted with markdown-table-formatter, as MegaLinter suggests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
main's #95 squash commit has the same tree as the #95 head this branch is built on, so every add/add conflict resolves to this branch's version. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno

Summary
This PR ports hal-ti's hardware-in-the-loop setup to hal-st for NUCLEO-WB55RG and NUCLEO-WBA55CG. It also fixes the hal-st driver bugs that the new suite found.
Validation app (
validation/)validation/firmware, targethal_st.validation_firmware):HALST_BUILD_EXAMPLESis on, forstm32wb55andstm32wba55.services/hilterminal on USART1 (ST-LINK VCP, 921600 baud).validation/PROTOCOL.md.validation/host, Python packagehal_st_validation):ad3-waveforms-bench.boards/nucleo_wb55rg.yaml,boards/nucleo_wba55cg.yaml) hold the wiring sets and expectations.known_gapsmarks the driver bugs that are still open.CN7/CN10and Arduino socket) and every solder bridge is taken from UM2435 Rev 2 (MB1355C), cross-checked with the STM32CubeWB example readmes. TIM2 CH2 / encoder B uses PA1 because PB3 (SWO) is on no header of a stock board. Seevalidation/README.md→ "NUCLEO-WB55RG wiring".0059646forservices/hil..vscodelaunch config can now debug WBA55 through a host ST-LINK GDB server.Driver fixes
PwmStmPeriod = 0failed the HALIS_TIM_PERIODassert (all MCUs). Centre-aligned PWM now usesARR = ticks / 2. Duty is scaled to the alignment's full count.DIRis written only afterCMS/SMSare cleared. TRGO, BDTR and BKIN are reset per user. An active-low break input is no longer inverted twice.AdcStm::SelectSingleConversion()restores single conversion for the other users. TIM1 drives TRGO2 for the ADC. The trigger table's missing TIM10 slot is added. A repeated channel with a different sampling time is now rejected (all ADCs).SpiMasterStm,SynchronousSpiMasterStmCSTARTis set once per transfer. A receive-only first transfer never started before.DmaStmSUSPFis cleared after a channel reset.UartStm& co.SWAPis always written. Destructors clear the interrupt enables, stop TX DMA, callHAL_UART_DeInitand gate the clock; this includes the synchronous UARTs.CR1updates are atomic. A receive overrun is cleared instead of aborting the firmware or causing an interrupt storm.GpioStmhal::Portvalue, which was wrong for port H. The G0 field width is also corrected.SynchronousQuadratureEncoderLpTimStmBehaviour changes to note
TimerBaseStm::TriggergainstriggerOutput2, which defaults to reset.PwmStm.Still open (documented in
validation/README.md)SynchronousUartStm: a send blocks with no timeout while CTS is held off. This is the only remainingknown_gapsentry (WBA55).uart.sendreports completion before the TX FIFO drains.SynchronousSpiMasterStmcan overflow the SPI v2 FIFO on receive-only transfers.SpiSlaveStmDmahasSPEhandling issues.Testing
-Werror, including the validation firmware on WB55 (~126 KB flash) and WBA55 (~120 KB flash).validation/README.md→ "Wiring sets".🤖 Generated with Claude Code
https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno